#include <memory>
#include <iostream>

using std::cout;
using std::endl;


void DeleteIntPtr(int * p)
{
    cout << __FUNCTION__ <<endl;
    delete p;
}


struct Foo{
    ~Foo(){
        cout << __FUNCTION__ << endl;
    }
};


/*struct A{*/
    //std::shared_ptr<A>GetSelf()
    //{
        //return std::shared_ptr<A>(this); //error
    //}
//};


struct A;
struct B;
struct A {
    std::shared_ptr<B> bptr;
    ~A(){ cout << "A is Deleted !" << endl; }
};

struct B {
    std::shared_ptr<A> aptr;
    ~B(){ cout << "B is Deleted !" << endl; }
};




int main(void)
{
    {

        //1. 初始化
        std::shared_ptr<int>p (new int[10]);
        std::shared_ptr<int> p2 = p;
        std::shared_ptr<int> ptr;
    }
    std::shared_ptr<int> foo = std::make_shared<int>(10);
    //获取原始指针
    int * ip = foo.get();
    cout << ip  << "\t" << *ip << endl;

    //指定删除器
    std::shared_ptr<int> p(new int, DeleteIntPtr);

    std::shared_ptr<int> pp (new int, [](int *p){ 
            cout << __FUNCTION__  << __LINE__ << endl;
            delete p;
            });

    {

    //std::shared_ptr<Foo> ff(new Foo[10]); //当我们使用 shared_ptr 管理动态数组时，需要指定删除函数。因为shared_ptr 的默认删除函数不支持数组对象
    std::shared_ptr<Foo> ff(new Foo[10], [](Foo *p){
            delete[] p;
            });
    }

    {
        //也可以使用 `std::default_delete` 作为删除函数
        std::shared_ptr<Foo> foo_arr(new Foo[10], std::default_delete<Foo[]>() );
    }

    //## 使用 shared_ptr 需要注意的问题

    //1. 不要用一个原始指针，去初始化多个 shared_ptr
    {
        int * ptr = new int;

        std::shared_ptr<int> p1(ptr);
        //std::shared_ptr<int> p2(ptr); // double free detected in tcache 2
    }
    //2. 不要在函数实参中创建 shared_ptr 
    // 因为C++ 的函数参数的计算顺序在不同的编辑器不同的约定下可能是不一样的，一般时从右到左，但也有可能是从左到右
    // windows 下的sutdio 和 Linux 下的GCC 都是从右到左执行的

    //3. 通过shared_from_this()返回this 指针。不要将this 作为 shared_ptr 返回出来，因为this 指针本质上是一个裸指针

    std::shared_ptr<A> sp1(new A);
    //std::shared_ptr<A> sp2 = sp1->GetSelf(); //double free detected in tcache 2
    std::shared_ptr<A> sp2 = sp1;//ok

    //4. 要避免循环引用，循环引用会带来内存泄漏

    {
        std::shared_ptr<A> ap(new A);
        std::shared_ptr<B> bp(new B);
        ap->bptr = bp;
        bp->aptr = ap;
    }


   return 0;
}













